#define _CRT_SECURE_NO_WARNINGS
#include "sokoban.h"

#define ROWS 10
#define COLS 11
//二维数组
//这个二维数组有10行，每一行有11列。
//这个二维数组的作用，用来保存地图上每个格子的类型
//每一个元素的值和地图上的每一个格子的类型是相互对应的。
//map[0][0]  #
char map[ROWS][COLS] = {
	"##########",
	"#  ####  #",
	"# X####  #",
	"#M       #",
	"######   #",
	"#  ####  #",
	"#        #",
	"#   ######",
	"#         ",
	"##########",
};

//保存小人当前的行坐标
int currentpersonrow = 3;
//保存小人当前的列坐标
int currentpersoncol = 1;

int main(int argc, const char* argv[])
{
	//1、第一件要做的事情就是显示我们的地图
	//我们用printf不能直接的进行打印，为什么不可以呀!
	//因为我们在进行后面移动小人的时候
	//要判断小人可不可以进行移动？
	//要知道小人的下一个位置是个什么类型的格子。
	//如果是一个空格就可以进行移动
	//如果是一个X，那么我们就要判断是否可以推箱子
	//如果是1个# 那么小人就不能移动。
	//所以我们必须要知道地图上的每1个格子的类型
	//那就把地图上的每一个格子的类型都进行存储起来呗
	//所以我们就可以使用一个二维数组来存储咋们格子上的每一个格子上的类型
	//2、要做的第一件事，就是显示游戏地图
	//所以我们将这个功能封装为1个函数
	int flag = 1;
	while (flag)
	{
		//调用这个函数，就可以将控制台上的内容
		system("cls");//这个函数的功能清空控制台上的所有的东西
		//在终端中才能运行程序
		ShowMap();
		if (map[8][9] == 'X')
		{
			printf("恭喜你取得了胜利\n");
				break; 
		}
	//3、让用户输入小人的前进方向。
		char dir = enterDirection();
		printf("你输入的方向是：%c", dir);
	//4、dir变量中存储的是用户输入的小人的前进方向
	//判断用户输入的前进方向，来把小人向不同的方向移动。
	// a w s d
		switch (dir)
		{
		case 'a':
		case 'A':
			moveToLeft();
		//将小人向左移动
		break;
		case 'w':
		case 'W':
			moveToUp();
		//将小人向上移动
			break;
		case 'd':
		case 'D':
			moveToRight();
		//将小人向右移动
			break;
		  case 's':
	      case 'S':
			moveToDown();
		//将小人向下移动
			break;
		case 'q':
		case 'Q':
		//结束游戏
			printf("唉！你的智商真低！！！\n");
			flag = 0;
			break;
	}
	//移动完毕之后重新的显示地图

   }

	system("pause");
	return 0;

}


void ShowMap()
{
	//显示游戏地图的原理:就是打印map中的元素
	for (int i = 0; i < ROWS; i++)
	{
		printf("%s\n", map[i]);
	}
}

char enterDirection()
{
      //1、输入小人前进的方向
	  //提示用户输入小人的方向
	printf("请输入小人的前进方向w.上  s.下   a.左    d.右   q.退出游戏\n");

	//接收输入小人的方向。
	char dir = 'a';
	//将scanf缓冲区中的数据清空，避免输入的时候会有一些问题
	rewind(stdin);
	scanf("%c", &dir);
	//2、将用户输入的方向返回
	return dir;
}


void moveToUp()//将小人向上进行移动
{
	//将小人向上移动
	//将小人向上移动的思路：
	//要做的一件事情就是要判断小人是否可以进行向上移动
	//如何判断小人能否向上移动
	//拿到小人下一个位置的坐标；小人现在的坐标是3行1列，拿到小人的下一个位置的坐标是2行1列
	//判断这个坐标格子是什么类型的格子
	//‘#’墙，不能移动； ‘ ’路，将小人向上移动；
	//'X'箱子：
	//     判断箱子是否可以推
	//     如果可以推，就推
	//     如果不可以推，没反应
	//1、要拿到小人下1个位置的坐标
	//   问题：如何拿到小人的下1个位置的坐标
	//   首先，应该拿到小人现在的坐标，通过小人现在的坐标，算出小人的下1个坐标
	//   小人现在的坐标是多少呢？小人的坐标是变化的，应该我们使用变量来进行保存小人的坐标，一开始的时候
	//   小人的坐标是3行2列，每移动一次，小人的坐标都会发生变化的。
	//    2、根据小人的当前坐标计算小人的下1个坐标的位置
	//    下1个行坐标是当前行坐标-1
	int nextpersonrow = currentpersonrow - 1;
	// 下1个列坐标是当前小人的列坐标不变。
	int nextpersoncol = currentpersoncol ;
	//3、判断下一个坐标在地图格子上是一个什么类型
	if (map[nextpersonrow][nextpersoncol] == ' ')
	{
		//说明是个路，移动小人，将下一个位置设置为M，将现在的位置设置为' '
		map[nextpersonrow][nextpersoncol] = 'M';
		map[currentpersonrow][currentpersoncol] = ' ';
		//这个时候小人的左边已经发生变化了。我们就需要将小人当前的坐标重新的设置
		currentpersonrow = nextpersonrow;
		currentpersoncol = nextpersoncol;
	}
	else if (map[nextpersonrow][nextpersoncol] == 'X')
	{
		//当箱子的下一个位置是一个路的时候就可以推；箱子的下一坐标是墙的话，就不能推
		//1、取出箱子的下1个坐标
	    // 箱子的当前坐标就是小人的的下1个坐标；就根据这个坐标求出箱子的下1个坐标
		int nextBoxrow = nextpersonrow - 1;
		int nextBoxcol = nextpersoncol;
		//2、判断箱子的下一个坐标的类型
		if (map[nextBoxrow][nextBoxcol] == ' ')
		{
			//说明箱子可以推了，推箱子的步骤：将箱子的下一个位置设置为箱子，箱子的当前的位置设置为人；将人的当前位置设置为空格
			map[nextBoxrow][nextBoxcol] = 'X';
			map[nextpersonrow][nextpersoncol] = 'M';
			map[currentpersonrow][currentpersoncol] = ' ';
			//改变小人当前的位置
			currentpersonrow = nextpersonrow;
			currentpersoncol = nextpersoncol;
		}
	}

}
void moveToLeft()//左
{
	int nextpersonrow = currentpersonrow ;
	// 下1个列坐标是当前小人的列坐标不变。
	int nextpersoncol = currentpersoncol-1;
	//3、判断下一个坐标在地图格子上是一个什么类型
	if (map[nextpersonrow][nextpersoncol] == ' ')
	{
		//说明是个路，移动小人，将下一个位置设置为M，将现在的位置设置为' '
		map[nextpersonrow][nextpersoncol] = 'M';
		map[currentpersonrow][currentpersoncol] = ' ';
		//这个时候小人的左边已经发生变化了。我们就需要将小人当前的坐标重新的设置
		currentpersonrow = nextpersonrow;
		currentpersoncol = nextpersoncol;
	}
	else if (map[nextpersonrow][nextpersoncol] == 'X')
	{
		//当箱子的下一个位置是一个路的时候就可以推；箱子的下一坐标是墙的话，就不能推
		//1、取出箱子的下1个坐标
		// 箱子的当前坐标就是小人的的下1个坐标；就根据这个坐标求出箱子的下1个坐标
		int nextBoxrow = nextpersonrow - 1;
		int nextBoxcol = nextpersoncol;
		//2、判断箱子的下一个坐标的类型
		if (map[nextBoxrow][nextBoxcol] == ' ')
		{
			//说明箱子可以推了，推箱子的步骤：将箱子的下一个位置设置为箱子，箱子的当前的位置设置为人；将人的当前位置设置为空格
			map[nextBoxrow][nextBoxcol] = 'X';
			map[nextpersonrow][nextpersoncol] = 'M';
			map[currentpersonrow][currentpersoncol] = ' ';
			//改变小人当前的位置
			currentpersonrow = nextpersonrow;
			currentpersoncol = nextpersoncol;
		}
	}
}
void moveToDown()//将小人进行向下移动
{
	int nextpersonrow = currentpersonrow +1;
	// 下1个列坐标是当前小人的列坐标不变。
	int nextpersoncol = currentpersoncol;
	//3、判断下一个坐标在地图格子上是一个什么类型
	if (map[nextpersonrow][nextpersoncol] == ' ')
	{
		//说明是个路，移动小人，将下一个位置设置为M，将现在的位置设置为' '
		map[nextpersonrow][nextpersoncol] = 'M';
		map[currentpersonrow][currentpersoncol] = ' ';
		//这个时候小人的左边已经发生变化了。我们就需要将小人当前的坐标重新的设置
		currentpersonrow = nextpersonrow   ;
		currentpersoncol = nextpersoncol;
	}
	else if (map[nextpersonrow][nextpersoncol] == 'X')
	{
		//当箱子的下一个位置是一个路的时候就可以推；箱子的下一坐标是墙的话，就不能推
		//1、取出箱子的下1个坐标
		// 箱子的当前坐标就是小人的的下1个坐标；就根据这个坐标求出箱子的下1个坐标
		int nextBoxrow = nextpersonrow+1 ;
		int nextBoxcol = nextpersoncol;
		//2、判断箱子的下一个坐标的类型
		if (map[nextBoxrow][nextBoxcol] == ' ')
		{
			//说明箱子可以推了，推箱子的步骤：将箱子的下一个位置设置为箱子，箱子的当前的位置设置为人；将人的当前位置设置为空格
			map[nextBoxrow][nextBoxcol] = 'X';
			map[nextpersonrow][nextpersoncol] = 'M';
			map[currentpersonrow][currentpersoncol] = ' ';
			//改变小人当前的位置
			currentpersonrow = nextpersonrow;
			currentpersoncol = nextpersoncol;
		}
	}
}
void moveToRight()//将小人向右移动
{
	int nextpersonrow = currentpersonrow ;
	// 下1个列坐标是当前小人的列坐标不变。
	int nextpersoncol = currentpersoncol+1;
	//3、判断下一个坐标在地图格子上是一个什么类型
	if (map[nextpersonrow][nextpersoncol] == ' ')
	{
		//说明是个路，移动小人，将下一个位置设置为M，将现在的位置设置为' '
		map[nextpersonrow][nextpersoncol] = 'M';
		map[currentpersonrow][currentpersoncol] = ' ';
		//这个时候小人的左边已经发生变化了。我们就需要将小人当前的坐标重新的设置
		currentpersonrow = nextpersonrow;
		currentpersoncol = nextpersoncol;
	}
	else if (map[nextpersonrow][nextpersoncol] == 'X')
	{
		//当箱子的下一个位置是一个路的时候就可以推；箱子的下一坐标是墙的话，就不能推
		//1、取出箱子的下1个坐标
		// 箱子的当前坐标就是小人的的下1个坐标；就根据这个坐标求出箱子的下1个坐标
		int nextBoxrow = nextpersonrow  ;
		int nextBoxcol = nextpersoncol+1;
		//2、判断箱子的下一个坐标的类型
		if (map[nextBoxrow][nextBoxcol] == ' ')
		{
			//说明箱子可以推了，推箱子的步骤：将箱子的下一个位置设置为箱子，箱子的当前的位置设置为人；将人的当前位置设置为空格
			map[nextBoxrow][nextBoxcol] = 'X';
			map[nextpersonrow][nextpersoncol] = 'M';
			map[currentpersonrow][currentpersoncol] = ' ';
			//改变小人当前的位置
			currentpersonrow = nextpersonrow;
			currentpersoncol = nextpersoncol;
		}
	}
}